実運用環境でcustom_schemaを使いたい場合のgenerate_schema_nameマクロを考えてみた
さがらです。
実運用環境でcustom_schemaを使いたい場合のgenerate_schema_name
マクロを考えてみたので、本記事でまとめてみます。
前置き:generate_schema_nameマクロの書き換えの必要性と難しさ
まず前置きとして、generate_schema_name
マクロの書き換えの必要性と難しさについて述べます。
例として、出力先のスキーマをdbt projectのフォルダごとに分けることなどを考え、custom_schemaを設定したとします。
このとき、デフォルトのgenerate_schema_name
マクロではcustom_schemaを設定すると{{ default_schema }}_{{ custom_schema_name | trim }}
の形で出力されてしまい、default_schema(profileなどで設定したスキーマ名)が作られるスキーマ名の先頭についてしまいます。
より具体的には、デフォルトのgenerate_schema_name
マクロは下記のように定義されています。(公式Docより引用)
{% macro generate_schema_name(custom_schema_name, node) -%} {%- set default_schema = target.schema -%} {%- if custom_schema_name is none -%} {{ default_schema }} {%- else -%} {{ default_schema }}_{{ custom_schema_name | trim }} {%- endif -%} {%- endmacro %}
「じゃあ{{ default_schema }}_{{ custom_schema_name | trim }}
を{{ custom_schema_name | trim }}
に書き換えればdefault_schemaが先頭につかなくなるじゃん」と思うかもしれませんが、単純にこうしてしまうと、開発環境でも本番環境でもcustom_schemaを設定している場合に同じスキーマに出力されてしまいカオスになってしまいます。せっかくdbtを導入して開発環境と本番環境をきれいに分離できるのに、これでは意味がないですよね。
そのため、出力先のスキーマを開発環境と本番環境で分けるには、target
を用いて開発環境と本番環境を考慮しつつ、generate_schema_name
マクロを書き換えていく必要があります。
書き換えの前提要件
上述の通りgenerate_schema_name
マクロをどう書き換えていくかをちゃんと考える必要があるのですが、「DWH上でどのようにデータベースとスキーマを管理するか」によって書き換え方が大きく変わってきます。
今回、私は以下の要件のもとgenerate_schema_name
マクロを書き換えてみました。
- 実行環境
- dbt:dbt Cloud Enterpriseエディション
- DWH:Snowflake
target
についてdev
:開発環境、dbt CloudでのIDEで実行する時prod
:本番環境、dbt CloudのProduction Environmentでジョブを実行する時
- データベース構成
RAW
データベース:生データを管理するSTAGING
データベース:dbtのプラクティスに沿った、カラム名の変更や型変更など最低限の加工を行ったデータを管理するDWH
データベース:One Big TableやDimensional Modelingなどのモデリングを行ったデータを管理するMART
データベース:各用途ごとにまとめられたデータマートを管理する
- 各データベースのスキーマ構成
- 本番環境のスキーマ:データの分類・用途・部署・プロジェクトなどの粒度でスキーマを作る
- 開発環境のスキーマ:各開発者ごとに
dbt_<名前>
のスキーマを作る ※デフォルト設定に準ずる - CI環境のスキーマ:dbt CloudのCIジョブの実行に合わせて自動でスキーマが生成・削除される(参考ブログ)
seed
の扱いについてseed
についても、開発環境と本番環境で出力先のスキーマを分けることを考える。この理由は、seed
もスキーマを分けないと、間違った内容のデータが本番環境に反映されてしまうリスクがあるため。- 本番環境のスキーマ:指定したcustom_schemaの名称でスキーマを作る
- 開発環境のスキーマ:指定したcustom_schemaに加えて各開発者ごとに
dbt_<名前>
のprefixをつけ、スキーマを作る
私が考えたgenerate_schema_nameマクロ
ということで前置きが長くなりましたが、私が考えたgenerate_schema_name
マクロを書き換えたコードがこちらになります。(書き換え方法ですが、./macros/
フォルダ内にget_custom_schema.sql
を作成し以下のコードを貼り付ければOKです。)
ポイントとしては、主に以下3つの観点で条件分岐を行っております。
- targetが
prod
かどうか node.resource_type
はseed
かどうかcustom_schema_name
は定義されているかどうか
{% macro generate_schema_name(custom_schema_name, node) %} {% set default_schema = target.schema %} {# targetが「prod」かつ対象のオブジェクトが「seed」かつcustom_schemaの定義ありの場合、seed向けの「custom_schema」に #} {% if target.name == 'prod' and node.resource_type == 'seed' and custom_schema_name is not none %} {{ custom_schema_name | trim }} {# targetが「prod」でないかつ対象のオブジェクトが「seed」かつcustom_schemaの定義ありの場合、「default_schema」を先頭に付けたseed向けの「custom_schema」に #} {% elif target.name != 'prod' and node.resource_type == 'seed' and custom_schema_name is not none %} {{ default_schema }}_{{ custom_schema_name | trim }} {# targetが「prod」かつcustom_schemaの定義ありの場合、「custom_schema」に #} {% elif target.name == 'prod' and custom_schema_name is not none %} {{ custom_schema_name | trim }} {# custom_schemaの定義なしの場合、「default_schema」に #} {% elif custom_schema_name is none %} {{ default_schema }} {# 上述の条件に合致しない(targetが「prod」でないがcustom_schemaの定義あり、など)の場合、「default_schema」に #} {% else %} {{ default_schema }} {% endif %} {% endmacro %}
実行してみるとどうなるか
では、実際に上述のgenerate_schema_name
マクロでどのように動くのかを見てみたいと思います。
各種ファイル・targetの設定
dbt_project.yml
※今回の検証に関連する箇所のみ記載
seeds: dbt_4layer_datastack_test: +database: sagara_4layer_test_raw +schema: seed_data models: dbt_4layer_datastack_test: +materialized: view # 下記以外のフォルダでModelを定義してしまった場合に、テーブルを作らないように staging: +materialized: view +database: sagara_4layer_test_staging jaffle_shop: +schema: jaffle_shop dwh: +materialized: table +database: sagara_4layer_test_dwh finance: +schema: finance mart: +materialized: table +database: sagara_4layer_test_mart finance: +schema: finance intermediate: +materialized: ehemeral
- 開発環境
target
:dev
schema
:dbt_ssagara
※default_schemaとなる
- 本番環境
target
:prod
を設定schema
:unavailable_schema
※default_schemaとなる。ただ、今回のgenerate_schema_name
マクロでは本番環境は基本的にcustom_schemaに格納されるため、使用不可であることがわかるスキーマ名を指定。
※dbt Cloudにおけるtarget
の設定については、下記ブログをご覧ください。
開発環境(target=dev)のとき
dbt CloudのIDE上で、dbt seed
とdbt build --select +supplies
というコマンドを続けて実行したあとのSnowflakeのデータベースとスキーマを確認してみます。
dbt seed
によって、生データを管理するSAGARA_4LAYER_TEST_RAW
データベースに、custom_schemaで指定したスキーマ名に開発者専用のスキーマ名をprefixとしてつけたDBT_SSAGARA_SEED_DATA
スキーマが作られています。
dbt build --select +supplies
によって、最低限の加工を行うSAGARA_4LAYER_TEST_STAGING
データベースに開発者専用のDBT_SSAGARA
スキーマが、データマートを管理するSAGARA_4LAYER_TEST_MART
データベースに
開発者専用のDBT_SSAGARA
スキーマが作られています。
本番環境(target=prod)のとき
dbt CloudでProductionと設定したEnvironmentのジョブで、dbt seed
とdbt build --select +supplies
というコマンドを続けて実行したあとのSnowflakeのデータベースとスキーマを確認してみます。(上述の開発環境におけるスキーマは削除してから実行しています。)
dbt seed
によって、生データを管理するSAGARA_4LAYER_TEST_RAW
データベースに、custom_schemaで指定した本番環境に該当するSEED_DATA
スキーマが作られています。
dbt build --select +supplies
によって、最低限の加工を行うSAGARA_4LAYER_TEST_STAGING
データベースにcustom_schemaで指定した本番用のJAFFLE_SHOP
スキーマが、データマートを管理するSAGARA_4LAYER_TEST_MART
データベースに
custom_schemaで指定した本番用のFINANCE
スキーマが作られています。
参考記事
generate_schema_name
マクロの書き換えについては、下記の記事が色々なパターンで書かれており非常に参考になります。(私も今回の検証に当たり何度も読ませて頂きました。)
ぜひこちらも併せてご覧ください。